"""推荐应用测试模块

包含推荐功能的测试用例。
"""

import pytest

from recommendations.services import Item, UserPreferences, get_recommendations


@pytest.fixture
def sample_items():
    """创建示例项目列表"""
    return [
        # 高度相关的项目
        Item(
            id=1,
            attributes={
                "name": "The Terminator",
                "genre": "Action",
                "director": "James Cameron",
                "actor": "Arnold Schwarzenegger",
                "year": 1984,
            },
        ),
        Item(
            id=2,
            attributes={
                "name": "Aliens",
                "genre": "Action",
                "director": "James Cameron",
                "actor": "Sigourney Weaver",
                "year": 1986,
            },
        ),
        Item(
            id=3,
            attributes={
                "name": "Predator",
                "genre": "Action",
                "director": "John McTiernan",
                "actor": "Arnold Schwarzenegger",
                "year": 1987,
            },
        ),
        Item(
            id=4,
            attributes={
                "name": "True Lies",
                "genre": "Action",
                "director": "James Cameron",
                "actor": "Arnold Schwarzenegger",
                "year": 1994,
            },
        ),
        Item(
            id=5,
            attributes={
                "name": "Blade Runner",
                "genre": "Sci-Fi",
                "director": "Ridley Scott",
                "actor": "Harrison Ford",
                "year": 1982,
            },
        ),
        # 相关性较低但仍有联系的项目
        Item(
            id=6,
            attributes={
                "name": "Commando",
                "genre": "Action",
                "director": "Mark L. Lester",
                "actor": "Arnold Schwarzenegger",
                "year": 1985,
            },
        ),
        Item(
            id=7,
            attributes={
                "name": "RoboCop",
                "genre": "Action",
                "director": "Paul Verhoeven",
                "actor": "Peter Weller",
                "year": 1987,
            },
        ),
        # 噪音项目（相关性较低）
        Item(
            id=8,
            attributes={
                "name": "Sleepless in Seattle",
                "genre": "Romance",
                "director": "Nora Ephron",
                "actor": "Tom Hanks",
                "year": 1993,
            },
        ),
        Item(
            id=9,
            attributes={
                "name": "Pride and Prejudice",
                "genre": "Drama",
                "director": "Joe Wright",
                "actor": "Keira Knightley",
                "year": 2005,
            },
        ),
        Item(
            id=10,
            attributes={
                "name": "The Notebook",
                "genre": "Romance",
                "director": "Nick Cassavetes",
                "actor": "Ryan Gosling",
                "year": 2004,
            },
        ),
        Item(
            id=11,
            attributes={
                "name": "La La Land",
                "genre": "Musical",
                "director": "Damien Chazelle",
                "actor": "Ryan Gosling",
                "year": 2016,
            },
        ),
        Item(
            id=12,
            attributes={
                "name": "The Godfather",
                "genre": "Crime",
                "director": "Francis Ford Coppola",
                "actor": "Al Pacino",
                "year": 1972,
            },
        ),
        Item(
            id=13,
            attributes={
                "name": "Casablanca",
                "genre": "Romance",
                "director": "Michael Curtiz",
                "actor": "Humphrey Bogart",
                "year": 1942,
            },
        ),
    ]


@pytest.fixture
def user_preferences():
    """创建用户偏好设置"""
    return UserPreferences(
        preferences={
            "genre": ["Action"],  # 专注于动作片
            "director": ["James Cameron"],  # 单一导演偏好
            "actor": ["Arnold Schwarzenegger"],  # 单一演员偏好
            "year": [1984, 1986, 1994],  # 只对特定年份感兴趣
        },
        watch_history=[1],  # 假设已经观看过The Terminator (id=1)
    )


def test_top_3_recommendations_with_more_noise(sample_items, user_preferences):
    """测试包含更多噪音时的前3个推荐"""
    recommendations = get_recommendations(user_preferences, sample_items, top_n=3)

    # 前3个推荐应该包括高度相关的项目，但也可能包括类似科幻片如Blade Runner
    expected_items = {"Aliens", "True Lies", "Predator"}
    acceptable_alternatives = {
        "Blade Runner"
    }  # Blade Runner由于科幻类型也相关

    # 提取前3个推荐的名称
    recommended_item_names = {rec.attributes["name"] for rec in recommendations}

    # 确保所有预期或可接受的项目都在推荐中
    assert (expected_items & recommended_item_names) or (
        acceptable_alternatives & recommended_item_names
    ), (
        f"Top recommendations should include: {expected_items} or alternatives like {acceptable_alternatives}, "
        f"but got: {recommended_item_names}"
    )


def test_recommendations_handle_more_noise(sample_items, user_preferences):
    """测试推荐如何处理更多噪音"""
    recommendations = get_recommendations(user_preferences, sample_items, top_n=5)

    # 确保噪音项目（浪漫/音乐剧）不会出现在前5个推荐中
    noisy_items = {
        "Sleepless in Seattle",
        "Pride and Prejudice",
        "The Notebook",
        "La La Land",
        "Casablanca",
    }

    # 检查是否有任何噪音项目在推荐中
    for item in recommendations:
        assert (
            item.attributes["name"] not in noisy_items
        ), f"Noisy item '{item.attributes['name']}' should not be in recommendations"

    # 确保返回了顶级相关项目
    expected_items = {"Aliens", "True Lies", "Predator", "Commando"}
    recommended_item_names = {rec.attributes["name"] for rec in recommendations}

    assert expected_items.issubset(
        recommended_item_names
    ), f"Expected relevant recommendations: {expected_items}, but got: {recommended_item_names}"
